//
//  CMNetworkService.swift
//  covermedia
//
//  Created by travel on 16/3/25.
//  Copyright © 2016年 covermedia. All rights reserved.
//

import Foundation

import ReachabilitySwift

public enum CMNetworkType: Int {
    case offline = 0
    case network2G
    case network3G
    case network4G
    case networkLTE
    case networkWiFi
    case unknown = -1
    
    public var name:String {
        switch self {
        case .offline: return "Offline"
        case .network2G: return "2G"
        case .network3G: return "3G"
        case .network4G, .networkLTE: return "4G"
        case .networkWiFi: return "WiFi"
        case .unknown: return "Unknown"
        }
    }
}

/// 网络状态服务
public class CMNetworkService:NSObject {
    fileprivate(set) var reachability:Reachability!
    fileprivate var statusChangeHandlers:[String: ((Bool) -> Void)] = [:]
    
    
    public static let shared = CMNetworkService()
    
    fileprivate class func buildReachability() -> Reachability?{
        return Reachability.init(hostname: CMURLConstant.reachabilityHost.urlConstant)
    }
    fileprivate override init() {
        super.init()
        reachability = CMNetworkService.buildReachability()
        CMNotification.addObserver(self, selector: #selector(self.handlerNetStatusChange), name: ReachabilityChangedNotification, object: nil)
    }
    
    deinit {
        reachability?.stopNotifier()
        reachability = nil
        CMNotification.removeObserver(self)
    }
    
    public func startService() {
        _ = try? reachability?.startNotifier()
    }
    
    public func isNetreachable() -> Bool {
        if reachability == nil {
            reachability = CMNetworkService.buildReachability()
        }
        return reachability?.isReachable ?? false
    }
    
    public func isReachableViaWiFi() -> Bool {
        return reachability?.isReachableViaWiFi ?? false
    }
    
    public func isReachableViaWWAN() -> Bool {
        return reachability?.currentReachabilityStatus == .reachableViaWWAN
    }
    
    
    /**
     当前网络类型
     
     - returns: 网络类型
     */
    public func networkType() -> CMNetworkType {
        switch(reachability.currentReachabilityStatus) {
        case .notReachable:
            return CMNetworkType.offline
        case .reachableViaWiFi:
            return CMNetworkType.networkWiFi
        case .reachableViaWWAN:
            return dataNetworkType()
        }
    }
    
    /**
     返回当前网络的类型
     
     - returns: 网络类型
     */
    fileprivate func dataNetworkType() -> CMNetworkType {
        let unknownDataType = CMNetworkType.unknown
        
        #if os(watchOS)
            return unknownDataType
        #endif
        
        let app = UIApplication.shared
        guard let subViews = ((app.value(forKey: "statusBar") as AnyObject?)?.value(forKey: "foregroundView") as? UIView)?.subviews else {
            return unknownDataType
        }
        
        guard let dataNetworkView = (subViews.filter{
            if let itemClass = NSClassFromString("UIStatusBarDataNetworkItemView"), $0.isKind(of: itemClass) {
                return true
            }
            return false
            }.first) else {
                return unknownDataType
        }
        
        if let dataNetworkType = dataNetworkView.value(forKey: "dataNetworkType") as? NSNumber {
            return CMNetworkType(rawValue: dataNetworkType.intValue) ?? unknownDataType
        }else{
            return unknownDataType
        }
    }
}


// MARK: - 处理网络状态变化
extension CMNetworkService {
    public func handlerNetStatusChange() {
        let isReachable = reachability?.isReachable ?? false
        for handler in statusChangeHandlers {
            handler.1(isReachable)
        }
    }
    
    public func startNetStatusObserver(_ observer:NSObject, block:@escaping ((Bool) -> Void)) {
        statusChangeHandlers[observer.identifierString] = block
    }
    
    public func stopNetStatusObserver(_ observer:NSObject) {
        statusChangeHandlers.removeValue(forKey: observer.identifierString)
    }
    
    /**
     处理网络状态变化
     
     - parameter observer: 观察者
     - parameter block:    处理函数
     */
    public class func startNetStatusObserver(_ observer:NSObject, block:@escaping ((Bool) -> Void)) {
        shared.statusChangeHandlers[observer.identifierString] = block
    }
    
    /**
     停止网络状态变化监测
     
     - parameter observer: 观察者
     */
    public class func stopNetStatusObserver(_ observer:NSObject) {
        shared.statusChangeHandlers.removeValue(forKey: observer.identifierString)
    }
}
